package com.hmy.finance.service.core.dto;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmy.finance.api.bo.core.request.PauseGenerateRequest;
import com.hmy.finance.api.bo.core.request.enums.FeeTypeEnum;
import com.hmy.finance.common.enums.BusinessBillTypeEnum;
import com.hmy.finance.common.enums.ProfitLossStatusEnum;
import com.hmy.finance.dal.mapper.DeviceProfitLossDetailMapper;
import com.hmy.finance.dal.po.DeviceProfitLossDetailPo;
import com.hmy.finance.dal.po.DeviceRentalRecordPo;
import com.hmy.finance.dal.po.ProfitLossRecordPo;
import com.hmy.finance.service.core.dto.vos.DeviceInfoVo;
import lombok.Data;

import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 报停损益生成请求业务逻辑处理参数
 *
 * @author songkf
 */
@Data
public class PauseGenerateDto implements Serializable {
    private static final long serialVersionUID = 6080476802539017620L;
    /**
     * 客户ID
     */
    private Long customerId;
    /**
     * 合同ID
     */
    private Long contractId;
    /**
     * 进场单ID
     */
    private Long entryFormId;
    /**
     * 业务单据ID
     */
    private Long businessBillId;
    /**
     * 报停设备ID集合
     */
    private List<Long> deviceIdList;
    /**
     * 报停设备信息集合
     */
    private List<DeviceInfoVo> deviceInfoList = new ArrayList<>();
    /**
     * 报停天数
     */
    private Double pauseDays;
    /**
     * 设备租赁记录集合
     */
    private List<DeviceRentalRecordPo> deviceRentalRecordPoList = new ArrayList<>();
    /**
     * 损益业务记录
     */
    private List<ProfitLossRecordPo> profitLossRecordPoList = new ArrayList<>();
    /**
     * 设备损益明细记录集合
     */
    private List<DeviceProfitLossDetailPo> deviceProfitLossDetailPoList = new ArrayList<>();

    /**
     * 组装报停损益生成业务逻辑处理参数
     *
     * @param request 报停损益生成请求
     * @return 报停损益生成业务逻辑处理参数
     */
    public static PauseGenerateDto buildPauseGenerateDto(PauseGenerateRequest request) {
        PauseGenerateDto dto = new PauseGenerateDto();
        dto.setCustomerId(request.getCustomerId());
        dto.setContractId(request.getContractId());
        dto.setBusinessBillId(request.getBusinessBillId());
        dto.setDeviceIdList(request.getDeviceIdList());
        dto.setDeviceInfoList(request.getDeviceInfoList().stream().map(vo -> {
            DeviceInfoVo vo1 = new DeviceInfoVo();
            vo1.setDeviceId(vo.getDeviceId());
            vo1.setEntryFormId(vo.getEntryFormId());
            vo1.setPauseDays(vo.getPauseDays());
            vo1.setPauseStartDate(vo.getPauseStartTime());
            vo1.setPauseEndDate(vo.getPauseEndTime());
            return vo1;
        }).collect(Collectors.toList()));
        dto.setPauseDays(request.getPauseDays());
        dto.setEntryFormId(request.getEntryFormId());
        return dto;
    }

    /**
     * 构建设备租赁记录Po LambdaQueryWrapper
     *
     * @return 设备租赁记录Po LambdaQueryWrapper
     * @author songkf
     */
    public Wrapper<DeviceRentalRecordPo> buildDeviceRentalRecordPoLambdaQueryWrapper() {
        return Wrappers.lambdaQuery(DeviceRentalRecordPo.class)
                .eq(DeviceRentalRecordPo::getCustomerId, this.customerId)
                .eq(DeviceRentalRecordPo::getContractId, this.contractId)
                .isNull(DeviceRentalRecordPo::getRentalEndTime)
                .and(wrapper -> {
                    this.deviceInfoList.forEach(deviceInfoVo -> {
                        wrapper.or(
                                wra -> wra.eq(DeviceRentalRecordPo::getDeviceId, deviceInfoVo.getDeviceId()).eq(DeviceRentalRecordPo::getEntryFormId, deviceInfoVo.getEntryFormId())
                        );
                    });
                })
                .orderByAsc(DeviceRentalRecordPo::getRentalStartTime);
    }

    /**
     * 组装报停损益生成业务逻辑处理参数
     *
     * @param identifierGenerator 主键生成器
     * @author songkf
     */
    public void assembleProfitLossRecord(DefaultIdentifierGenerator identifierGenerator, DeviceProfitLossDetailMapper deviceProfitLossDetailMapper) {
        ProfitLossRecordPo profitLossRecordPo = new ProfitLossRecordPo();
        profitLossRecordPo.setCustomerId(this.getCustomerId());
        profitLossRecordPo.setContractId(this.getContractId());
        profitLossRecordPo.setBusinessBillId(this.getBusinessBillId());
        profitLossRecordPo.setBusinessBillType(BusinessBillTypeEnum.PAUSE);
        profitLossRecordPo.setFeeType(FeeTypeEnum.PAUSE_FEE);
        profitLossRecordPo.setStatus(ProfitLossStatusEnum.ALREADY_EFFECTIVE);
        profitLossRecordPo.setFeeIncurredTime(LocalDateTime.now());
        profitLossRecordPo.setId(identifierGenerator.nextId(profitLossRecordPo));
        profitLossRecordPo.setTotalFeeAmount(BigDecimal.valueOf(this.getPauseDays()));
        //遍历设备租赁记录集合，组装设备损益明细记录.根据报停的总天数，从今日开始往后推
        this.getDeviceRentalRecordPoList().forEach(deviceRentalRecordPo -> {
//            //默认从今天开始
//            LocalDateTime now = LocalDateTime.now();
//            //查询该设备最大的报停发生日期
//            LocalDateTime maxPauseDate = deviceProfitLossDetailMapper.selectMaxPauseDate(deviceRentalRecordPo.getId());
//            if (maxPauseDate != null && maxPauseDate.isAfter(now)) {
//                now = maxPauseDate;
//            }
            DeviceInfoVo infoVo = this.getDeviceInfoList().stream().filter(deviceInfoVo -> deviceInfoVo.getDeviceId().equals(deviceRentalRecordPo.getDeviceId())).findFirst().get();
            int times = (int) (infoVo.getPauseDays()) + (infoVo.getPauseDays() % 1 != 0 ? 1 : 0);

            //遍历pauseDays
            for (int i = 0; i < times; i++) {
                DeviceProfitLossDetailPo deviceProfitLossDetailPo = new DeviceProfitLossDetailPo();
                deviceProfitLossDetailPo.setBusinessBillType(BusinessBillTypeEnum.PAUSE);
                deviceProfitLossDetailPo.setProfitLossRecordId(profitLossRecordPo.getId());
                deviceProfitLossDetailPo.setDeviceId(deviceRentalRecordPo.getDeviceId());
                deviceProfitLossDetailPo.setDeviceNo(deviceRentalRecordPo.getDeviceExtensionInfo().getDeviceNo());
                deviceProfitLossDetailPo.setDeviceRentalRecordId(deviceRentalRecordPo.getId());
                if (i == times - 1) {
                    deviceProfitLossDetailPo.setFee(BigDecimal.valueOf(infoVo.getPauseDays() - i));
                    deviceProfitLossDetailPo.setDays(infoVo.getPauseDays() - i);
                } else {
                    deviceProfitLossDetailPo.setFee(BigDecimal.valueOf(1));
                    deviceProfitLossDetailPo.setDays(1d);
                }
                deviceProfitLossDetailPo.setFeeIncurredTime(infoVo.getPauseStartDate().plusDays(i));
                deviceProfitLossDetailPo.setContractId(this.getContractId());
                deviceProfitLossDetailPo.setContractNo(deviceRentalRecordPo.getContractNo());
                deviceProfitLossDetailPo.setFeeType(FeeTypeEnum.PAUSE_FEE);
                deviceProfitLossDetailPo.setId(identifierGenerator.nextId(deviceProfitLossDetailPo));
                this.getDeviceProfitLossDetailPoList().add(deviceProfitLossDetailPo);
            }
        });
        this.getProfitLossRecordPoList().add(profitLossRecordPo);
    }

    public Wrapper<DeviceRentalRecordPo> getCheckRentalStatusWrapper() {
        return Wrappers.lambdaQuery(DeviceRentalRecordPo.class)
                .and(wrapper -> {
                    this.deviceInfoList.forEach(deviceInfoVo -> {
                        wrapper.or(
                                wra -> wra.eq(DeviceRentalRecordPo::getDeviceId, deviceInfoVo.getDeviceId()).eq(DeviceRentalRecordPo::getEntryFormId, deviceInfoVo.getEntryFormId())
                                        //精确报停后，不允许同一天出现多次报停
                                        .notExists("select 1 from device_profit_loss_detail where  device_rental_record_id = device_rental_record.id and fee_type = '" + FeeTypeEnum.PAUSE_FEE + "' and fee_incurred_time >= '" + deviceInfoVo.getPauseStartDate().toLocalDate().atTime(0, 0, 0) + "' and fee_incurred_time <= '" + deviceInfoVo.getPauseEndDate().toLocalDate().atTime(23, 59, 59) + "'")
                        );
                    });
                })
                .isNull(DeviceRentalRecordPo::getRentalEndTime);
    }
}
